#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "consulta/motorConsultas.h"
#include "fileSystem/file.h"
#include "fileSystem/matrix.h"

#define POR_PERSONAS 0
#define ERROR_ENTRADA -1
#define ACTOR_NO_ENCONTRADO -1

/*
 * procesar_Entrada
 * Recibe argumentos de entrada y los valida
 * Devuelve:
 *          ERROR_ENTRADA (-1) si hay errores con los argumentos ingresados
 *          POR_PERSONAS (0) si se ejecuta "--to"
 *          Grados a calcular si se ejecuta "--degree"
 */

int procesar_Entrada(int arguc,char** arguv) {

	        if (arguc!=5)     // se necesitan 5 argumentos para ejecutar
	            {
	                printf("\nError en cantidad de argumentos para ejecutar.\n\n");
	                return ERROR_ENTRADA;
	            }

	        if (strcmp((arguv[1]),"--from")!=0)   // verifica segundo argumento
	            {
	                printf("\nEl segundo argumento debe ser --from.\n\n");
	                return ERROR_ENTRADA;
	            }

	        if ((strcmp((arguv[3]),"--to") == 0))  // cálculo entre personas
	        {

                return POR_PERSONAS;
	        }

	        if(strcmp(arguv[3],"--degree") == 0){   // cálculo en base a grados de separación

	        	int i;

	        	for (i=0; i<strlen(arguv[4]);i++){

                if ((isdigit(arguv[4][i])) == 0){   // verifica que sea un numero

	        		printf("\nEl argumento siguiente a --degree debe ser un numero.\n\n");

	        		return ERROR_ENTRADA;

					}

                }

	           	int grado = atoi(arguv[4]);    // paso a integer

	        	if ( (grado == 0) || (grado > 127) ) {

	        		printf("\nEl grado de separacion debe ser un valor entre 1 y 127.\n\n");

	        		return ERROR_ENTRADA;
	        	}

	        	return grado;

	        }

	        printf("\nEl cuarto argumento debe ser --to o --degree.\n\n");

	return ERROR_ENTRADA;
}

/*
 * realizarConsulta
 * Recibe en numConsulta q tipo de consulta debe realizar, por personas (POR_PERSONAS)
 * o en base a tantos grados de separacion (numConsulta > 0)
 * Tambien recibe dos strings, para realizar la relacion entre ellos
 * Si la consulta es por grados de separacion el contenido del segundo string no importa
 * luego recibe los nombres de los archivos de personas, de peliculas y de matriz de relaciones
 * No valida numConsulta
 */

void realizarConsulta(int numConsulta, char *primero, char *segundo, const char *archPersonas, const char *archPeliculas, const char *archMatriz){

	fHandler *personas = R_OPEN(archPersonas,READ);   // abro archivo de actores

	fHandler *peliculas = R_OPEN(archPeliculas,READ); // abro archivo de peliculas

	mHandler *matriz = M_OPEN(archMatriz, READ);    // abro matriz para lectura

	if ( (!personas) || (!peliculas) || (!matriz) ) {
		printf("\nNo se encuentran los archivos necesarios.\n\n");
		return;
	}

	int resultadoConsulta;

	TRelacion elemLista;

	TLista listaResultado;

	int id1,id2;

	if (numConsulta == POR_PERSONAS){

		 id1 = R_BUSQBINARIA(personas,primero);

		 id2 = R_BUSQBINARIA(personas,segundo);

		 if (id1 == ACTOR_NO_ENCONTRADO || id2 == ACTOR_NO_ENCONTRADO){

			 R_CLOSE(personas);

			 R_CLOSE(peliculas);

	         M_CLOSE(matriz);

	         printf("\nNo se encuentra la persona ingresada.\n\n");

			 return;
		 }

			if (strcmp(primero,segundo)==0){

				printf("\nLos nombres ingresados corresponden a la misma persona.\n\n");

				R_CLOSE(personas);

                R_CLOSE(peliculas);

				M_CLOSE(matriz);

				return;
			}

		resultadoConsulta = consultarPorPersona(&listaResultado, matriz, peliculas, personas, id1, id2);

		if (resultadoConsulta == -2){

			printf("\nNo hay relacion entre las personas ingresadas.\n\n");

			 R_CLOSE(personas);

		     R_CLOSE(peliculas);

	         M_CLOSE(matriz);

			return;
		}

          int primero = 1;

          int cantidad = 0;

          int max = -1;

          lista_MoverCorriente(&listaResultado,LSC_PRIMERO);

          do{

          max++;

          }while(lista_MoverCorriente(&listaResultado,LSC_SIGUIENTE));  //para contar elementos de la lista

          printf("\nDegree of separation: %i\n\n",max);

          lista_MoverCorriente(&listaResultado,LSC_PRIMERO);

          do{

        	  lista_ElemCorriente(listaResultado,&elemLista);

        	  if (primero)

        		  primero = 0;

        	  else

        		  printf("%s (%s)\n",elemLista.nombre,elemLista.profesion);   // el primero no imprime esto

        	  if (cantidad<max){    // para que no imprima el ultimo

        		  printf("%s (%s) was in %s with ",elemLista.nombre,elemLista.profesion,elemLista.pelicula);

        		  cantidad++;

				  }

          }while(lista_MoverCorriente(&listaResultado,LSC_SIGUIENTE));

          lista_Vaciar(&listaResultado);

          R_CLOSE(personas);

          R_CLOSE(peliculas);

          M_CLOSE(matriz);

        return; // termina consulta por personas
	}

	// SINO REALIZA CONSULTA POR GRADOS

	 id1 = R_BUSQBINARIA(personas,primero);

     if (id1 == ACTOR_NO_ENCONTRADO){

				 R_CLOSE(personas);

				 R_CLOSE(peliculas);

		         M_CLOSE(matriz);

		         printf("\nNo se encuentra la persona ingresada.\n\n");

				 return;
			 }

     consultarPorGrados(matriz, peliculas, personas, id1, numConsulta);

         R_CLOSE(personas);

         R_CLOSE(peliculas);

         M_CLOSE(matriz);

return;  // termina consulta por grados

}

int main(int argc,char** argv){

	int resultado = procesar_Entrada(argc,argv);

	if (resultado != ERROR_ENTRADA)
		realizarConsulta(resultado,argv[2],argv[4],"_person","_films","matrix.dat");

	return 0;
}
